package me.dwk.dandan.function.functions;

import java.util.ArrayList;
import java.util.Collection;
import java.util.LinkedList;
import java.util.List;
import java.util.concurrent.ThreadLocalRandom;

import org.apache.commons.lang3.StringUtils;

import lombok.extern.slf4j.Slf4j;
import me.dwk.dandan.function.AbstractFunction;
import me.dwk.dandan.function.CompoundVariable;
import me.dwk.dandan.function.ThreadVariables;
import me.dwk.dandan.function.exception.InvalidVariableException;

/**
 * Provides a RandomFromMultiResult function which returns a random element from
 * a multi valued extracted variable. Those kind of variable are extracted by: -
 * Regular Expression extractor - JSON extractor - CSS/JQuery extractor - XPath
 * Extractor
 *
 * @since 3.1
 */
@Slf4j
public class RandomFromMultipleVars extends AbstractFunction {

	private static final List<String>	desc		= new LinkedList<>();
	private static final String			KEY			= "__RandomFromMultipleVars";	//$NON-NLS-1$
	private static final String			SEPARATOR	= "\\|";						//$NON-NLS-1$
	static {
		desc.add("Source Variable(s) (use | as separator)"); //$NON-NLS-1$
		desc.add("Target Variable"); //$NON-NLS-1$
	}

	private CompoundVariable	variablesNamesSplitBySeparator;
	private CompoundVariable	varName;

	/**
	 * No-arg constructor.
	 */
	public RandomFromMultipleVars() {}

	/** {@inheritDoc} */
	@Override
	public String execute() throws InvalidVariableException {

		String variablesNamesSplitBySeparatorValue = variablesNamesSplitBySeparator.execute().trim();
		ThreadVariables vars = getVariables();
		String outputValue = "";
		String separator = "";
		if (vars != null) { // vars will be null on TestPlan
			List<String> results = new ArrayList<>();
			String[] variables = variablesNamesSplitBySeparatorValue.split(SEPARATOR);
			for (String varName : variables) {
				if (!StringUtils.isEmpty(varName)) {
					extractVariableValuesToList(varName, vars, results);
				}
			}

			if (results.size() > 0) {
				int randomIndex = ThreadLocalRandom.current().nextInt(0, results.size());
				outputValue = results.get(randomIndex);
			} else {
				if (log.isDebugEnabled()) {
					log.debug("RandomFromMultiResult didn't find <var>_matchNr in variables :'"
									+ variablesNamesSplitBySeparatorValue
									+ "' using separator:'"
									+ separator
									+ "', will return empty value");
				}
			}

			if (varName != null) {
				final String varTrim = varName.execute().trim();
				if (varTrim.length() > 0) {
					vars.put(varTrim, outputValue);
				}
			}
		}
		return outputValue;

	}

	/**
	 * @param variableName
	 *            String
	 * @param vars
	 *            {@link ThreadVariables}
	 * @param results
	 *            {@link List} where results are stored
	 * @throws NumberFormatException
	 */
	private void extractVariableValuesToList(	String variableName,
												ThreadVariables vars,
												List<String> results) throws NumberFormatException {
		String matchNumberAsStr = vars.get(variableName + "_matchNr");
		int matchNumber = 0;
		if (!StringUtils.isEmpty(matchNumberAsStr)) {
			matchNumber = Integer.parseInt(matchNumberAsStr);
		}
		if (matchNumber > 0) {
			for (int i = 1; i <= matchNumber; i++) {
				results.add(vars.get(variableName + "_" + i));
			}
		} else {
			String value = vars.get(variableName);
			if (!StringUtils.isEmpty(value)) {
				results.add(value);
			}
		}
	}

	/** {@inheritDoc} */
	@Override
	public void setParameters(Collection<CompoundVariable> parameters) throws InvalidVariableException {
		checkParameterCount(parameters, 1, 2);
		Object[] values = parameters.toArray();
		variablesNamesSplitBySeparator = (CompoundVariable) values[0];
		if (values.length > 1) {
			varName = (CompoundVariable) values[1];
		}
	}

	/** {@inheritDoc} */
	@Override
	public String getReferenceKey() {
		return KEY;
	}

	/** {@inheritDoc} */
	@Override
	public List<String> getArgumentDesc() {
		return desc;
	}
}
